import os
import requests
from bs4 import BeautifulSoup
import tkinter as tk
from tkinter import messagebox, filedialog
from tkinter.ttk import Treeview, Progressbar

def search_music(event=None):
    query = entry.get()
    if not query:
        messagebox.showwarning("警告", "请输入歌曲名")
        return

    try:
        search_url = f"https://www.mvmp3.com/so.php?wd={query}"
        response = requests.get(search_url)
        response.raise_for_status()

        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 查找所有的<li>元素，这些包含了歌曲的信息
        songs = soup.find_all('li')

        valid_songs = []
        for song in songs:
            name_tag = song.find('a', class_='url')
            if name_tag:
                valid_songs.append(song)
        valid_songs = valid_songs[:20]
        song_download_links.clear()
        listbox.delete(0, tk.END)

        for song in valid_songs:
            name_tag = song.find('a', class_='url')
            song_name_and_artist = name_tag.get_text(strip=True)
            detail_url = name_tag['href']
            
            # 提取 lkid 从 href 中
            lkid = detail_url.split('/')[-1].split('.')[0]
            download_link = f"https://www.mvmp3.com/down.php?ac=music&id={lkid}"
            
            song_download_links.append((song_name_and_artist, download_link))
            listbox.insert(tk.END, song_name_and_artist)

    except requests.RequestException as e:
        messagebox.showerror("错误", f"搜索失败: {e}")

def add_to_queue(event):
    selected_indices = listbox.curselection()
    if not selected_indices:
        messagebox.showwarning("警告", "请选择一首或多首歌曲")
        return

    for index in selected_indices:
        name, link = song_download_links[index]
        if any(queue_tree.item(item)['values'][1] == link for item in queue_tree.get_children()):
            messagebox.showwarning("警告", f"歌曲 '{name}' 已经在待下载队列中")
        else:
            queue_tree.insert("", tk.END, values=(name, link))

def clear_queue():
    queue_tree.delete(*queue_tree.get_children())
    update_progress_info()

def set_default_path():
    global default_save_path
    default_save_path = filedialog.askdirectory(title="选择默认下载路径")
    if default_save_path:
        path_label.config(text=f"默认下载路径: {default_save_path}")

def update_progress(message):
    progress_label.config(text=message)
    root.update_idletasks()

def update_progress_info(downloaded=0, total=0):
    progress_info_label.config(text=f"已下载: {downloaded}/{total} 首歌曲")

def download_all():
    if not default_save_path:
        messagebox.showwarning("警告", "请先设置默认下载路径")
        return

    items = queue_tree.get_children()
    if not items:
        messagebox.showwarning("警告", "待下载列表为空")
        return

    progress_bar['value'] = 0
    progress_bar.update_idletasks()
    total_items = len(items)
    downloaded_count = 0
    
    for i, item in enumerate(items):
        name, link = queue_tree.item(item, 'values')
        save_path = os.path.join(default_save_path, f"{name}.mp3")
        try:
            music_response = requests.get(link, stream=True)
            music_response.raise_for_status()
            
            content_length = music_response.headers.get('content-length')
            if content_length and content_length.isdigit():
                total_size = int(content_length)
            else:
                total_size = None
            
            downloaded_size = 0
            
            with open(save_path, 'wb') as f:
                for chunk in music_response.iter_content(chunk_size=8192):
                    f.write(chunk)
                    downloaded_size += len(chunk)
                    if total_size:
                        progress = (downloaded_size / total_size) * 100
                    else:
                        progress = (i + 1) / total_items * 100
                    progress_bar['value'] = min(progress, 100)
                    progress_bar.update_idletasks()
                    update_progress(f"正在下载: {name} ({progress:.2f}%)")
                    
        except Exception as e:
            messagebox.showerror("错误", f"下载失败: {e}")
            break
        
        downloaded_count += 1
        progress_bar['value'] = (downloaded_count / total_items) * 100
        progress_bar.update_idletasks()
        update_progress(f"完成: {name}")
        update_progress_info(downloaded_count, total_items)
    
    messagebox.showinfo("成功", "所有歌曲下载完成")

# 创建主窗口
root = tk.Tk()
root.title("音乐下载器")
root.geometry("800x750")

# 默认下载路径
default_save_path = ""

# 搜索框
entry_label = tk.Label(root, text="歌曲名:")
entry_label.grid(row=0, column=0, padx=10, pady=5)

entry = tk.Entry(root, width=40)
entry.grid(row=0, column=1, padx=10, pady=5)
entry.bind("<Return>", search_music)  # 绑定回车键事件

# 搜索按钮
search_button = tk.Button(root, text="搜索", command=search_music)
search_button.grid(row=0, column=2, padx=10, pady=5)

# 设置默认下载路径按钮
path_button = tk.Button(root, text="设置默认下载路径", command=set_default_path)
path_button.grid(row=1, column=0, padx=10, pady=5)

# 显示默认下载路径
path_label = tk.Label(root, text="默认下载路径: 未设置")
path_label.grid(row=1, column=1, columnspan=2, padx=10, pady=5)

# 歌曲列表
listbox_frame = tk.Frame(root)
listbox_frame.grid(row=2, column=0, columnspan=3, padx=10, pady=10)

scrollbar = tk.Scrollbar(listbox_frame, orient=tk.VERTICAL)
listbox = tk.Listbox(listbox_frame, width=70, height=10, yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)

listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

# 绑定双击事件以添加到待下载队列
listbox.bind("<Double-Button-1>", lambda event: add_to_queue(None))

# 待下载队列
queue_label = tk.Label(root, text="待下载队列")
queue_label.grid(row=3, column=0, columnspan=3, padx=10, pady=5)

columns = ("Name", "Link")
queue_tree = Treeview(root, columns=columns, show='headings', height=10)
queue_tree.heading("Name", text="歌曲名称及艺术家")
queue_tree.heading("Link", text="下载链接")
queue_tree.column("Name", width=400)
queue_tree.column("Link", width=350)
queue_tree.grid(row=4, column=0, columnspan=3, padx=10, pady=10)

# 清空待下载队列按钮
clear_button = tk.Button(root, text="清空待下载队列", command=clear_queue)
clear_button.grid(row=5, column=0, padx=10, pady=5)

# 下载所有按钮
download_all_button = tk.Button(root, text="下载所有", command=download_all)
download_all_button.grid(row=5, column=2, padx=10, pady=5)

# 进度条
progress_bar = Progressbar(root, orient=tk.HORIZONTAL, length=760, mode='determinate')
progress_bar.grid(row=6, column=0, columnspan=3, padx=10, pady=10)

# 进度信息标签
progress_label = tk.Label(root, text="")
progress_label.grid(row=7, column=0, columnspan=3, padx=10, pady=5)

# 总进度信息标签
progress_info_label = tk.Label(root, text="已下载: 0/0 首歌曲")
progress_info_label.grid(row=8, column=0, columnspan=3, padx=10, pady=5)

# 存储歌曲信息和下载链接
song_download_links = []

# 运行主循环
root.mainloop()



